<?php
/**
 * Created by PhpStorm.
 * User: LukaChen
 * Date: 18/4/29
 * Time: 下午6:02
 */

namespace EasyShortUrl;

use Illuminate\Support\Facades\Request;
use EasyShortUrl\Model\ShortUrl;
use EasyShortUrl\Model\ShortUrlAccess;
use EasyShortUrl\Exception\EasyShortUrlException;

class EasyShortUrl
{
    const STR_SHUFFLE_62 = '9uDsa6I2GzjMCRg8PXc4ZHFhtmVniwLWYeKyqO7blpQ5BES3TUdAx0Jrk1fvNo';

    /**
     * 构建短网址
     * @param $code
     * @return string
     */
    private function buildShortUrl($code)
    {
        return rtrim(config("shorturl.esu_domain"),"/") . '/s/' . $code;
    }

    /**
     * 长网址缩短为短网址
     * long url to short url
     * @param $longUrl
     * @param $accessKey
     * @return string
     * @throws EasyShortUrlException
     */
    public function toShort($longUrl)
    {
        $this->validateAccess(config('shorturl.esu_web_admin_access_key'), $longUrl);

        $longUrlHash = md5($longUrl . config('shorturl.esu_web_admin_access_key'));

        $existsCode = ShortUrl::where('long_url_hash', $longUrl)->value('code');
        if ($existsCode) {
            return $this->buildShortUrl($existsCode);
        }

        $model = ShortUrl::create([
            'code' => '',
            'long_url' => $longUrl,
            'long_url_hash' => $longUrlHash,
            'request_num' => 0,
            'ip' => Request::ip(),
            'access_key' => config('shorturl.esu_web_admin_access_key'),
        ]);

        $code = $this->base10To62($model->id);

        ShortUrl::where('id', $model->id)->update(['code' => $code]);

        return $this->buildShortUrl($code);
    }

    /**
     * 短网址还原为长网址
     * short url restore long url
     * @param $code
     * @return bool
     */
    public function toLong($code)
    {
        $this->validateAccessByCode($code);

        $res = ShortUrl::whereRaw("binary code = '".$code."'")->first();
        if ($res) {
            return $res->long_url;
        }
        throw new EasyShortUrlException('网址不存在');
    }

    /**
     * 跳转次数递增
     * redirect num ++
     * @param $code
     * @return bool
     */
    public function requestNum($code)
    {
        ShortUrl::whereRaw("binary code = '".$code."'")->increment('request_num');
    }

    /**
     * 10 进制数转自定义 62 进制数
     * decimal to custom 62 hex
     * @param $num
     * @return string
     */
    public function base10To62($num)
    {
        $res = '';
        while ($num > 0) {
            $res = substr(self::STR_SHUFFLE_62, $num % 62, 1) . $res;
            $num = floor($num / 62);
        }
        return $res;
    }

    /**
     * 校验授权
     * validate access
     * @param $accessKey
     * @param $longUrl
     * @throws EasyShortUrlException
     */
    private function validateAccess($accessKey, $longUrl)
    {
        $parseResult = parse_url($longUrl);
        if (!isset($parseResult['host']) || empty($parseResult['host'])) {
            throw new EasyShortUrlException('error long url');
        }
        $res = ShortUrlAccess::where('access_key',$accessKey)->where('access_domain',$parseResult['host'])->first();
        if (empty($res)) {
            throw new EasyShortUrlException('not access');
        }
    }

    /**
     * 校验跳转授权
     * validate access by code
     */
    private function validateAccessByCode($code)
    {
        $res = ShortUrl::whereRaw("binary code = '".$code."'")->first();
        if (empty($res)) {
            throw new EasyShortUrlException('not found long url');
        }
        $this->validateAccess($res->access_key, $res->long_url);
    }
}
